/***********************************************************************
 * Module:  Case.java
 * Author:  nabil
 * Purpose: Defines the Class Case
 ***********************************************************************/
package model.jeu_de_dame;
import model.util.Couleur;
import model.util.Direction;
import java.util.*;
import model.gestion_mouvement.ICase;

/**
 * <b>Case représente une case du jeu de dame
 * </b>
  * <p>
 * Une case est caractérisé par les informations suivantes :
 * <ul>
 * <li>La couleur de la case</li>
 * <li>La positionX de la case dans le damier</li>
 * <li>La positionY de la case dans le damier</li>
 * <li>Une référence vers le damier</li>
 * </ul>
 * </p>
 * @see Damier
 * @see Piece
 * @author nabil mansouri
 * @version 2.0
 */
public class Case extends Observable implements ICase{
   /**
         * La couleur de la case "blanc" ou "noir"
         * 
         * @see Case#Case(int, int, String, Damier) 
         * @see Case#getCouleur() 
         */
   private Couleur couleur;
      /**
         * La position x de la case dans le damier
         * 
         * @see Case#Case(int, int, String, Damier) 
         * @see Case#getPositionX() 
         */
   private int positionX;
    /**
         * La position y de la case dans le damier
         * 
         * @see Case#Case(int, int, String, Damier) 
         * @see Case#getPositionY() 
         */
   private int positionY;
       /**
         * Le damier auquel la case appartient
         * 
         * @see Case#Case(int, int, String, Damier) 
         * @see Case#getDamier() 
         * @see Case#getMesVoisines() 
         */
   private boolean accessible;
   private Damier monDamier;
   
       /**
         * Constructeur Case.
         * <p>
         * Initialisation de la case avec les coordonnées de la case x et y. Cette méthode affecte
         * la couleur à la case et une référence vers le Damier.
         * </p>
         *  
         */
   
   private HashMap<Direction,Case> mesVoisines;
   public Case(int x, int y, Couleur couleur,Damier monDamier)
   {
       this.monDamier = monDamier;
       this.positionX = x;
       this.positionY = y;
       this.couleur = couleur;
       this.mesVoisines = new HashMap<Direction,Case>();
   }
   
  /**
     * Retourne la couleur de la case
     * @return La couleur de la case "blanc" ou "noir"
     */
    public Couleur getCouleur() {
        return couleur;
    }

      /**
     * Retourne le damier auquel la case appartient
     * @return Le damier auquel la case appartient
     */
    public Damier getDamier()
    {
        return this.monDamier;
    }
     /**
     * Retourne la positionX de la case dans le damier
     * @return La positionX de la case dans le damier
     */
    public int getPositionX() {
        return positionX;
    }

    /**
     * Retourne la positionY de la case dans le damier
     * @return La positionY de la case dans le damier
     */
    public int getPositionY() {
        return positionY;
    }

   /**
     * Retourne la piece qui est sur cette case (si il y en a une)
     * @return La piece qui est sur cette case (si il y en a une) ou null sinon
     */
    public Piece getPiece() {
        try
        {
            return this.monDamier.getPiece(positionX, positionY);
        }catch(Exception e)
        {
            return null;
        }
    }


    
    
   /**
     * Retourne si la case contient une piece ou non.
     * @return true si une piece est sur la case false sinon
     */
    public boolean hasPiece()
    {
        try
        {
                if(this.monDamier.getPiece(positionX, positionY)!=null)
                    return true;
         }catch (Exception e)
         {
             
            return false;
         }
        return false;
    }
    

       /**
     * Retourne si la case est de la couleur de jeu autorisé.
     * @return true si la case est autorisée false sinon
     * 
     */
    public boolean isCaseAutorise()
    {
        return this.monDamier.getCouleurJeu()==couleur;
    }
    
    
        /**
     * Retourne la liste des cases diagonalements voisines à cette case (dans toutes les directions) 
     * La profondeur définit le nombre de cases voisines par diagonales (soit la longueur du chemin par diagonale)
     * Ici la profondeur est infini, soit on regarde toutes les cases qui sont voisines.
     * @return Une liste de liste de cases (soit une liste par diagonale)
     * @see Case#getMesVoisines(int) 
     */
    public ArrayList<ArrayList<Case>> getMesVoisines()
    {  
        return getMesVoisines(Integer.MAX_VALUE);
    }
    
   /**
     * Retourne la liste des cases diagonalements voisines à cette case (dans toutes les directions) 
     * La profondeur définit le nombre de cases voisines par diagonales (soit la longueur du chemin par diagonale)
     * @return Une liste de liste de cases (soit une liste par diagonale)
     * @see Case#getMesVoisines() 
     */
    public ArrayList<ArrayList<Case>> getMesVoisines(int profondeur)
    {   
        int [] tableau = {-1,1};
        ArrayList<ArrayList<Case>> lesDiagonales = new ArrayList<ArrayList<Case>>();
        for(int dx : tableau)
        {
            for(int dy : tableau)
            {
                ArrayList<Case> uneDiagonale = new ArrayList<Case>();
                int x = this.getPositionX()+dx;
                int y = this.getPositionY()+dy;
                int i = 0;
                try
                {
                    while(i<profondeur)
                    {
                        Case c = this.monDamier.getCase(x, y);
                        uneDiagonale.add(c);
                        x += dx;
                        y+= dy;
                        i++;
                    }
                }catch(Exception e)
                {
                    
                }
                
                lesDiagonales.add(uneDiagonale);
            }
        }
        return lesDiagonales;
    }
    
    public void setVoisine(Direction dir, Case c)
    {
        this.setChanged();
        this.mesVoisines.put(dir, c);
    }
    
    public Case getVoisine(Direction dir) throws Exception
    {
        if(!mesVoisines.containsKey(dir))
            throw new Exception("La case dans cette direction n'existe pas!");
        return this.mesVoisines.get(dir);
    }
    public Direction getDirectionVers(ICase destination) throws Exception
    {
        int deltaX = destination.getPositionX()-this.positionX;
        int deltaY = destination.getPositionY()-this.positionY;
        if(deltaX<0)
        {
            if(deltaY<0)
            {
                return Direction.NORD_OUEST;
            }
            else if(deltaY>0)
            {
                return Direction.SUD_OUEST;
            }else
            {
                return Direction.OUEST;
            }
        }
        else if(deltaX>0)
        {
            if(deltaY<0)
            {
                return Direction.NORD_EST;
            }
            else if(deltaY>0)
            {
                return Direction.SUD_EST;
            }else
            {
                return Direction.EST;
            }
        }else
        {
            if(deltaY<0)
            {
                return Direction.NORD;
            }
            else if(deltaY>0)
            {
                return Direction.SUD;
            }else
            {
                throw new Exception("La case destination egale case depart!");
            }
        }
        
    }

    @Override
    public boolean equals(Object obj) {
        try
        {
            if(!(obj instanceof Case))
                return false;
            Case c = (Case)obj;
            if(c.getPositionX()==this.positionX 
                    && this.positionY == c.getPositionY() 
                    && c.getCouleur() == this.couleur)
                return true;
            else 
                return false;
        }catch(Exception e)
        {
            return false;
        }
    }
    
    
    
    
    public boolean isAccessible()
    {
        return accessible;
    }

    public void setAccessible(boolean accessible) {
        this.setChanged();
        this.accessible = accessible;
    }
    
    
    public void maj()
    {
        if(this.hasChanged())
            this.notifyObservers();
    }
    
    public void setChangement()
    {
        this.setChanged();
    }
    
}